﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using MusicStore.Domain.POCO;

namespace MusicStore.Domain.Concrete
{
    public class ShoppingCartManager
    {
        private EFDbContext db;


        public ShoppingCartManager()
        {
            db = new EFDbContext();
        }

        public void AddToCart(int albumIdToAdd, string userName)
        {
            // Get the matching cart and album instances
            ShoppingCart shoppingCartOnWhichTheAlbumNeedsToBeAdded = GetShoppingCartWithCartItems(userName);

            // Check shopping cart exists, else create new shopping cart
            if (shoppingCartOnWhichTheAlbumNeedsToBeAdded == null)
            {
                shoppingCartOnWhichTheAlbumNeedsToBeAdded = new ShoppingCart();
                shoppingCartOnWhichTheAlbumNeedsToBeAdded.User = userName;
                shoppingCartOnWhichTheAlbumNeedsToBeAdded.CartItems = new List<CartItem>();
                db.ShoppingCarts.Add(shoppingCartOnWhichTheAlbumNeedsToBeAdded);
            }

            // Add to shopping cart
            CartItem itemToAdd = shoppingCartOnWhichTheAlbumNeedsToBeAdded.CartItems.Find(c => c.AlbumId == albumIdToAdd);
            if (itemToAdd != null)
            {
                itemToAdd.Quantity++;
            }
            else
            {
                itemToAdd = new CartItem();
                itemToAdd.AlbumId = albumIdToAdd;
                itemToAdd.DateCreated = System.DateTime.Now;
                itemToAdd.Quantity = 1;
                itemToAdd.ShoppingCart = shoppingCartOnWhichTheAlbumNeedsToBeAdded;
                itemToAdd.ShoppingCartId = shoppingCartOnWhichTheAlbumNeedsToBeAdded.ShoppingCartId;
                shoppingCartOnWhichTheAlbumNeedsToBeAdded.CartItems.Add(itemToAdd);
            }

            // Save changes
            db.SaveChanges();
        }

        public int RemoveFromCart(int albumIdToRemove, string userName)
        {
            // Get the matching ShoppingCart
            ShoppingCart matchingShoppingCart = GetShoppingCartWithCartItems(userName);

            if (matchingShoppingCart == null)
                throw new InvalidOperationException("Cannot retrieve the shoppingCart of user " + userName);

            //Find the matching ShoppingCartItem
            CartItem itemToRemove = matchingShoppingCart.CartItems.Find(ci => ci.AlbumId == albumIdToRemove);
            int itemCount = 0;

            if (itemToRemove != null)
            {
                if (itemToRemove.Quantity > 1)
                {
                    itemToRemove.Quantity--;
                    itemCount = itemToRemove.Quantity;
                }
                else
                    db.CartItems.Remove(itemToRemove);

                // Save changes
                db.SaveChanges();
            }

            return itemCount;
        }

        public void EmptyDeleteCart(string userName)
        {
            ShoppingCart shoppingCartToEmpty = GetShoppingCartWithCartItems(userName);

            if (shoppingCartToEmpty != null)
            {
                db.ShoppingCarts.Remove(shoppingCartToEmpty); // Cascading delete cartitems by required relationship!

                // Save changes
                db.SaveChanges();
            }
        }

        public ShoppingCart GetShoppingCartWithCartItems(string userName)
        {
            return db.ShoppingCarts.Include(sc => sc.CartItems).SingleOrDefault<ShoppingCart>(sc => sc.User == userName);
        }

        public int GetTotalQuantity(string userName)
        {
            ShoppingCart shoppingCartOfUser = GetShoppingCartWithCartItems(userName);

            int? result = db.CartItems
                              .Include(ci => ci.ShoppingCart)
                              .Where<CartItem>(ci => ci.ShoppingCart.User == userName)
                              .Sum<CartItem>(ci => (int?)ci.Quantity);

            return result ?? 0;
        }

        public decimal GetTotalPrice(string userName)
        {
            decimal? result = db.CartItems
                              .Include(ci => ci.ShoppingCart)
                              .Where<CartItem>(ci => ci.ShoppingCart.User == userName)
                              .Sum<CartItem>(ci => (int?)ci.Quantity * ci.Album.Price);

            return result ?? Decimal.Zero;
        }

        // When a user has logged in, migrate their shopping cart to
        // be associated with their username
        public bool MigrateCart(string oldUserGuid, string newUserName)
        {
            bool succeded = false;

            ShoppingCart cartToChange = GetShoppingCartWithCartItems(oldUserGuid);
            if (cartToChange != null && cartToChange.CartItems != null && cartToChange.CartItems.Count != 0)
            {
                //Check of de nieuwe user al een shoppingcart heeft. Zo ja, voeg daar alle items aan toe
                //      en verwijder bestaande shoppingCart
                ShoppingCart cartOfNewUser = GetShoppingCartWithCartItems(newUserName);
                if (cartOfNewUser == null)
                    cartToChange.User = newUserName;
                else
                {
                    foreach (CartItem cartItemOfOldShoppingCart in cartToChange.CartItems)
                    {
                        cartItemOfOldShoppingCart.ShoppingCartId = cartOfNewUser.ShoppingCartId;
                    }
                    db.ShoppingCarts.Remove(cartToChange);
                }

                db.SaveChanges();
                
                succeded = true;
            }
            else
                succeded = false;

            return succeded;
        }

        public void DeleteShoppingCartOfUser(string userName)
        {
            EmptyDeleteCart(userName);
        }

        public void FillOrderWithShoppingCardInfo(Order newOrder)
        {
            ShoppingCart existingShoppingCard = GetShoppingCartWithCartItems(newOrder.Username);

            decimal orderTotal = 0;

            // Iterate over the items in the cart, adding the order details for each
            newOrder.OrderDetails = new List<OrderDetail>();

            foreach (var item in existingShoppingCard.CartItems)
            {
                OrderDetail newOrderDetail = new OrderDetail()
                {
                    AlbumId = item.AlbumId,
                    OrderId = newOrder.OrderId,
                    UnitPrice = item.Album.Price,
                    Quantity = item.Quantity
                };

                // Set the order total of the shopping cart
                orderTotal += (item.Quantity * item.Album.Price);

                newOrder.OrderDetails.Add(newOrderDetail);
            }

            // Set the order's total to the orderTotal count
            newOrder.Total = orderTotal;
        }

        public void FillOrder(ref Order newOrder)
        {
            ShoppingCart shoppingCartToOrder = GetShoppingCartWithCartItems(newOrder.Username);

            decimal orderTotal = 0;

            // Iterate over the items in the cart, adding the order details for each
            newOrder.OrderDetails = new List<OrderDetail>();
            foreach (var item in shoppingCartToOrder.CartItems)
            {
                var orderDetail = new OrderDetail
                {
                    AlbumId = item.AlbumId,
                    OrderId = newOrder.OrderId,
                    UnitPrice = item.Album.Price,
                    Quantity = item.Quantity
                };

                // Set the order total of the shopping cart
                orderTotal += (item.Quantity * item.Album.Price);

                newOrder.OrderDetails.Add(orderDetail);
            }

            // Set the order's total to the orderTotal count
            newOrder.Total = orderTotal;

            //// Empty the shopping cart
            //this.EmptyCart(userName);

            //// Return the OrderId as the confirmation number
            //return newOrder.OrderId;
        }
    }
}
